package com.open.rbac.config.security.filter;

import java.util.List;
import java.util.Optional;

import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import com.open.center.common.constant.OpenConstant;
import com.open.center.jwt.model.JwtUser;
import com.open.center.jwt.provider.JwtProvider;
import com.open.rbac.config.security.MeUsernamePasswordAuthenticationToken;

/**
 * JWT认证过滤器
 *
 * @author Riche's
 * @since 2025/5/25
 */
@Slf4j
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final List<String> notFilters;

    private final JwtProvider jwtProvider;

    private final AntPathMatcher matcher = new AntPathMatcher();

    @Override
    protected void doFilterInternal(@NonNull HttpServletRequest request,
                                    @NonNull HttpServletResponse response,
                                    @NonNull FilterChain filterChain) {
        try {
            log.info("{}", request.getRequestURL());
            Optional<String> token = resolveToken(request);
            if (token.isPresent()) {
                // 验证Token有效性
                JwtUser jwtUser = jwtProvider.parseUser(token.get());
                List<String> roleIds = OpenConstant.castList(jwtUser.getter().get("roleIds"), String.class);
                List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList(roleIds.toArray(new String[0]));
                MeUsernamePasswordAuthenticationToken authenticationToken =
                        new MeUsernamePasswordAuthenticationToken(jwtUser.getUsername(), null, authorities);
                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                authenticationToken.setId(jwtUser.getUserId());
                authenticationToken.setUsername(jwtUser.getUsername());
                authenticationToken.setRealName(jwtUser.getRealName());
                authenticationToken.setRoleIds(roleIds);

                // 使用新的上下文，否则会抛出异常：Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead
                SecurityContext newContext = SecurityContextHolder.createEmptyContext();
                newContext.setAuthentication(authenticationToken);
                SecurityContextHolder.setContext(newContext);
            }
            filterChain.doFilter(request, response);
        } catch (Exception e) {
            log.error("Token校验失败：{}", e.getMessage(), e);
        }
    }


    private Optional<String> resolveToken(HttpServletRequest request) {
        String authorizationToken = request.getHeader(OpenConstant.AUTHORIZATION);
        return OpenConstant.resolveToken(authorizationToken);
    }

    @Override
    protected boolean shouldNotFilter(@NonNull HttpServletRequest request) {
        return notFilters.stream().anyMatch(uri -> matcher.match(uri, request.getRequestURI()));
    }
}
